iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
Software Development

程式基礎概念討論系列 第 21

[DAY 21] 踏進物件導向大門的類別

  • 分享至 

  • xImage
  •  

昨天,我們介紹了結構,而今天,我們要討論的則是它的全面升級版的類別 (Class)。我們可以把類別理解為是以結構的相似概念為基礎,為了對應更多更複雜的狀況而追加了物件導向的相關特性後的進階版本。

類別與結構的最大差異便是來自於物件導向中的物件 (Object),也就是說,我們可以像是宣告變數一樣直接宣告結構來使用,但類別卻必須要透過建構物件才可以使用,這使它的定位從原來的 「變數與函式的組合」 昇華為 「變數與函式的組合 (物件) 的定義」。這是什麼意思呢?這就像是生物學中的生物分類法一樣,我們透過描述生物 (物件)特徵 (變數)行為 (函式) 來定對牠是屬於什麼的生物分類 (類別)

現在我們來看一下類別與結構在使用上有什麼差別:[C#]

using System;

public class StructAndClassExample
{
    
    public struct BirdStruct {
        public string name; // 我們不可在結構中為變數指定初始值
        public int wings;
        public int legs;
        public void fly() {
            ...
        }
        public void speak() {
            Console.WriteLine(name + ": Quack!");
        }
    }
    
    public class BirdClass {
        public string name = "bird class"; // 我們可以在類別中為變數指定初始值
        public int wings;
        public int legs;
        public void fly() {
            ...
        }
        public void speak() {
            Console.WriteLine(name + ": Quack!");
        }
    }
    
    public static void Main(string[] args)
    {
        // 我們必須在宣告結構才能指定變數的值
        BirdStruct birdStruct;
        birdStruct.name = "bird struct";
        birdStruct.wings = 2;
        birdStruct.legs = 2;
        birdStruct.speak(); // 顯示:bird struct: Quack!
        // 我們必須使用 new 關鍵字來為它們建立獨立的物件
        BirdClass birdClass = new BirdClass();
        // 當然,我們也可以在建立物件後指定或改變物件中的變數的值
        birdClass.wings = 2;
        birdClass.legs = 2;
        birdClass.speak(); // 顯示:bird class: Quack!
    }
}

在上面的例子中我們透過使用類別與結構來包裝一樣的變數及函式來比較它們的差別:

1. 我們不能在結構中為變數指定值,但類別可以
結構是「變數與函式的組合」,因此這代表了它跟一般的變數一樣,是在宣告它時程式才會為我們準備「容器」,因此我們沒辦法提前把資料放進去。相對的,類別是「變數與函式的組合的定義」,它的目的不再是作為容器存在,而是定義了所有屬於該類別的物件都會有這樣的變數和函式,舉例來說,在生物上我們定義了鳥類 (類別) 都會有翅膀 (特徵/變數) 跟可以叫 (行為/函式),那麼當我們現在創造 (建立) 了一隻屬於鳥類的生物 (物件) 時,那隻生物並必定會有翅膀跟可以叫。因此,我們可以在類別中為變數指定值,但這並不是把資料放進去,而是讓每一個該類別的物件在剛建立時都必定會擁有這些資料

2. 我們在宣告結構後可以直接使用,但類別需要建立物件
由於結構的概念跟一般的變數類似,因此當我們宣告它後,程式便會為我們準備好「容器」,讓我們直接使用。而類別由於只是一個抽象的定義,因此在我們實際的為它建立物件後,它才會實際的存在在程式中

小插曲:時代在進步,結構也在進步

實際上,在過去物件導向的概向剛出現的時代,結構只是一種單純的「資料的組合」,我們甚至不能在結構中放入函式。但隨著時代的改變,程式語言透過互相借鑒並引入其他語言的優點來改良自身的不足,這使結構的概念不再只局限於變數,更包含了函式。筆者在查詢資料時發現,在近年,結構更新增了越來越多跟類別相似的特質,如建構子 (Constructor) 及介面 (Interface) 的繼承 (Inheritance) 等。說不定在不久的將來,結構與類別會逐漸變成相同的概念吧。

建構子

在上面我們提到了建構子 (Constructor),它是什麼呢?建構子本身是類別在建立物件時所使用的函式,也就是我們實際上是透過它去根據我們的定義 (類別) 來為我們的物件宣告變數及指定變數的值,而這個過程也被稱作初始化 (Initialization),意思是為在變數使用前先為它指定一個值。我們也可以自訂建構子來讓我們在建立物件時可以做更多事情。一般來說,建構子的函式名稱是固定的,通常跟類別的名稱一樣,不過有些語言則使用了初始化這單字來代表建構子的函式,如 Python 便使用了初始化的簡寫 init 作為建構子的函式。

自訂建構子的例子:[C#]

using System;

public class ClassConstructorExample
{
    
    public class BirdClass {
        public string name = "bird class";
        public int wings;
        public int legs;
        // 自訂建構子的函式
        public BirdClass() {
            wings = 2;
            legs = 2;
            speak(); // 我們可以呼叫其他的函數
        }
        public void fly() {
            
        }
        public void speak() {
            Console.WriteLine(name + ": Quack!");
        }
    }
    
    public static void Main(string[] args)
    {
                // 這個部分是在呼叫建構子的函式來建立我們要的物件
                // 當我們有自訂建構子時,便會自動變成呼叫我們自訂的版本
                                //  V
        BirdClass birdClass = new BirdClass(); // 顯示:bird class: Quack!
    }

其他語言的自訂建構子雖然寫法上不一樣,但背後的邏輯是一樣的:[Python]

class BirdClass:
    # 自訂建構子的函式
    def __init__(self):
        # 由於 Python 是動態語言,我們需要在建構子的函式中宣告變數及指定值
        self.name = "bird class"
        self.wings = 2
        self.legs = 2
        self.speak() # 我們可以呼叫其他的函數

    def speak(self):
        print(self.name + ": Quack!")
        
            # 這個部分也是在呼叫建構子的函式來建立我們要的物件
            # V
bird_class = BirdClass()

類別與結構的最大分歧點

正如前文提到,在近年來說,類別與結構變得越來越接近,那為什麼現在部分的語言仍然會同時提供兩者呢?這就要提到它們之間最大的差異 - 儲存方法了。當我們在執行程式時,程式暫時儲存的資料可能會以這兩種方法中的其中一種來儲存:一種方法是存取速度快但儲存空間較少的 Stack;另一種方法是存取速度慢但儲存空間較大的 Heap。結構跟一般的變數都是使用 Stack 來儲存的,因此較適合我們在簡單處理資料時使用;類別是使用 Heap 來儲存的,因此較適合我們在需要使用複雜的函式來處理資料時使用。

除此之外,類別還包含了物件導向的特性,分別是繼承 (Inheritance)抽象化 (Abstraction)多型 (Polymorphism)封裝 (Encapsulation)。當我們需要使用這些特性時,也會選擇使用類別。


上一篇
[DAY 20] 把變數組合起來的結構
下一篇
[DAY 22] 繼承把物件重複的定義都整合在一起
系列文
程式基礎概念討論30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言